{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "import torch\n",
    "import torch.nn as nn \n",
    "import d2lzh as d2l \n",
    "\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "\n",
    "def vgg_block(num_convs,in_channels,out_channels):\n",
    "    blk = []\n",
    "\n",
    "    for i in range(num_convs):\n",
    "        if i == 0:\n",
    "            blk.append(nn.Conv2d(in_channels,out_channels,kernel_size=3,padding=1))\n",
    "        else:\n",
    "            blk.append(nn.Conv2d(out_channels,out_channels,kernel_size=3,padding=1))\n",
    "        blk.append(nn.ReLU())\n",
    "    blk.append(nn.MaxPool2d(kernel_size=2,stride=2)) # 降维，宽和高减半\n",
    "\n",
    "    return nn.Sequential(*blk)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "vgg_block_1 output shape: torch.Size([1, 64, 112, 112])\nvgg_block_2 output shape: torch.Size([1, 128, 56, 56])\nvgg_block_3 output shape: torch.Size([1, 256, 28, 28])\nvgg_block_4 output shape: torch.Size([1, 512, 14, 14])\nvgg_block_5 output shape: torch.Size([1, 512, 7, 7])\nfc output shape: torch.Size([1, 10])\n"
    }
   ],
   "source": [
    "conv_arch = ((1,1,64),(1,64,128),(2,128,256),(2,256,512),(2,512,512))\n",
    "\n",
    "#经过5次maxpool，宽和高变成224 / 2^5 = 7\n",
    "fc_features = 512 * 7 *7\n",
    "fc_hidden_units = 4096\n",
    "\n",
    "def vgg11(conv_arch,fc_features,fc_hidden_units=4096):\n",
    "    net = nn.Sequential()\n",
    "    for i,(num_convs,in_channels,out_channels) in enumerate(conv_arch):\n",
    "        net.add_module('vgg_block_' + str(i+1),vgg_block(num_convs,in_channels,out_channels))\n",
    "    net.add_module('fc',nn.Sequential(d2l.FlattenLayer(),\n",
    "        nn.Linear(fc_features,fc_hidden_units),\n",
    "        nn.ReLU(),\n",
    "        nn.Dropout(0.5),\n",
    "        nn.Linear(fc_hidden_units,fc_hidden_units),\n",
    "        nn.ReLU(),\n",
    "        nn.Dropout(0.5),\n",
    "        nn.Linear(fc_hidden_units,10)\n",
    "        ))\n",
    "    return net\n",
    "\n",
    "net = vgg11(conv_arch,fc_features,fc_hidden_units)\n",
    "x = torch.rand(1,1,224,224)\n",
    "\n",
    "# named_children获取一级子模块及其名称\n",
    "# named_modules会返回所有子模块，包括子模块的子模块\n",
    "for name,blk in net.named_children():\n",
    "    x = blk(x)\n",
    "    print(name,'output shape:',x.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "Sequential(\n  (vgg_block_1): Sequential(\n    (0): Conv2d(1, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): ReLU()\n    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (vgg_block_2): Sequential(\n    (0): Conv2d(8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): ReLU()\n    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (vgg_block_3): Sequential(\n    (0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): ReLU()\n    (2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (3): ReLU()\n    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (vgg_block_4): Sequential(\n    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): ReLU()\n    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (3): ReLU()\n    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (vgg_block_5): Sequential(\n    (0): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (1): ReLU()\n    (2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n    (3): ReLU()\n    (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n  )\n  (fc): Sequential(\n    (0): FlattenLayer()\n    (1): Linear(in_features=3136, out_features=512, bias=True)\n    (2): ReLU()\n    (3): Dropout(p=0.5)\n    (4): Linear(in_features=512, out_features=512, bias=True)\n    (5): ReLU()\n    (6): Dropout(p=0.5)\n    (7): Linear(in_features=512, out_features=10, bias=True)\n  )\n)\n"
    }
   ],
   "source": [
    "ratio = 8\n",
    "\n",
    "small_conv_arch = [\n",
    "    (1,1,64//ratio),\n",
    "    (1,64//ratio,128//ratio),\n",
    "    (2,128//ratio,256//ratio),\n",
    "    (2,256//ratio,512//ratio),\n",
    "    (2,512//ratio,512//ratio)\n",
    "    ]\n",
    "net = vgg11(small_conv_arch,fc_features//ratio,fc_hidden_units//ratio)\n",
    "print(net)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "output_type": "stream",
     "name": "stdout",
     "text": "training on  cuda\nepoch 1, loss 0.6001, train acc 0.776,test acc 0.867,time 80.0\nepoch 2, loss 0.1734, train acc 0.874,test acc 0.885,time 77.5\nepoch 3, loss 0.1002, train acc 0.890,test acc 0.901,time 77.7\nepoch 4, loss 0.0668, train acc 0.902,test acc 0.898,time 78.7\nepoch 5, loss 0.0492, train acc 0.910,test acc 0.909,time 77.8\n"
    }
   ],
   "source": [
    "batch_size = 32\n",
    "train_iter,test_iter = d2l.load_data_fashion_mnist(batch_size,resize=224)\n",
    "\n",
    "lr,num_epochs = 0.001,5\n",
    "optimizer = torch.optim.Adam(net.parameters(),lr=lr)\n",
    "d2l.train_ch5(net,train_iter,test_iter,batch_size,optimizer,device,num_epochs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7-final"
  },
  "orig_nbformat": 2,
  "kernelspec": {
   "name": "python37764bitpytorchnotebookconda6e7a8693df0d4d92aca09d521275d23a",
   "display_name": "Python 3.7.7 64-bit ('pytorch_notebook': conda)"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}